package org.tong.common.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.tong.common.utils.JsonUtil;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Component
@Aspect
public class ApiOperationLogAspect{

    @Pointcut("@annotation(org.tong.common.aspect.ApiOperationLog)")
    public void apiOperationLog(){}

    @Around("apiOperationLog()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        try {
            long startTime = System.currentTimeMillis();
            MDC.put("traceId", UUID.randomUUID().toString());
            //获取被请求类和方法名
            String className = joinPoint.getTarget().getClass().getSimpleName();
            String methodName = joinPoint.getSignature().getName();
            //获取请求参数
            Object[] args = joinPoint.getArgs();
            String argsJson = Arrays.stream(args).map(toJson()).collect(Collectors.joining(","));
            //功能描述
            String description = getApiOperationLogDescription(joinPoint);
            //打印请求参数信息
            log.info("=====请求开始：[{}]，入参：{}，请求类：{}，请求方法：{}=====",description,argsJson,className,methodName);
            Object result = joinPoint.proceed();
            long executionTime = System.currentTimeMillis() - startTime;
            //打印响应参数信息
            log.info("=====请求结束：[{}]，耗时：{}ms，出参：{}=====",description,executionTime,JsonUtil.toJsonString(result));
            return result;
        }finally {
            MDC.clear();
        }

    }

    private String getApiOperationLogDescription(ProceedingJoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        Method method = signature.getMethod();
        ApiOperationLog apiOperationLog = method.getAnnotation(ApiOperationLog.class);
        return apiOperationLog.description();
    }

    private Function<Object,String> toJson() {
        return JsonUtil::toJsonString;
    }
}
